#include <string.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>

#include "overlay_list.h"
#include "linked_list.h"
#include "utils_string.h"
#include "file.h"

static void freeEntryData(void *data)
{
    OverlayEntryData *e_data = (OverlayEntryData *)data;
    if (e_data)
    {
        if (e_data->name)
            free(e_data->name);
        if (e_data->image_name)
            free(e_data->image_name);
        if (e_data->viewport_rotate)
            free(e_data->viewport_rotate);
        if (e_data->viewport_width)
            free(e_data->viewport_width);
        if (e_data->viewport_height)
            free(e_data->viewport_height);
        if (e_data->viewport_x)
            free(e_data->viewport_x);
        if (e_data->viewport_y)
            free(e_data->viewport_y);
        free(e_data);
    }
}

LinkedListEntry *OverlayListFindEntryByName(LinkedList *list, const char *name)
{
    if (!list || !name)
        return NULL;

    LinkedListEntry *entry = LinkedListHead(list);

    while (entry)
    {
        OverlayEntryData *data = (OverlayEntryData *)LinkedListGetEntryData(entry);

        if (data->name && strcmp(data->name, name) == 0)
            return entry;

        entry = LinkedListNext(entry);
    }

    return NULL;
}

static void getEntryData(LinkedList *list, OverlayEntryData **data, char *section, char *key, char *value)
{
    if (section)
    {
        *data = (OverlayEntryData *)calloc(1, sizeof(OverlayEntryData));
        if (*data)
        {
            LinkedListAdd(list, *data);
            (*data)->name = section;
            section = NULL;
        }
    }
    else if (*data)
    {
        if (strcmp(key, "image_name") == 0)
        {
            if (!(*data)->image_name)
            {
                (*data)->image_name = value;
                value = NULL;
            }
        }
        else if (strcmp(key, "viewport_rotate") == 0)
        {
            if (!(*data)->viewport_rotate)
            {
                (*data)->viewport_rotate = (int *)malloc(sizeof(int));
                if ((*data)->viewport_rotate)
                    *((*data)->viewport_rotate) = StringToDecimal(value);
            }
        }
        else if (strcmp(key, "viewport_width") == 0)
        {
            if (!(*data)->viewport_width)
            {
                (*data)->viewport_width = (int *)malloc(sizeof(int));
                if ((*data)->viewport_width)
                    *((*data)->viewport_width) = StringToDecimal(value);
            }
        }
        else if (strcmp(key, "viewport_height") == 0)
        {
            if (!(*data)->viewport_height)
            {
                (*data)->viewport_height = (int *)malloc(sizeof(int));
                if ((*data)->viewport_height)
                    *((*data)->viewport_height) = StringToDecimal(value);
            }
        }
        else if (strcmp(key, "viewport_x") == 0)
        {
            if (!(*data)->viewport_x)
            {
                (*data)->viewport_x = (int *)malloc(sizeof(int));
                if ((*data)->viewport_x)
                    *((*data)->viewport_x) = StringToDecimal(value);
            }
        }
        else if (strcmp(key, "viewport_y") == 0)
        {
            if (!(*data)->viewport_y)
            {
                (*data)->viewport_y = (int *)malloc(sizeof(int));
                if ((*data)->viewport_y)
                    *((*data)->viewport_y) = StringToDecimal(value);
            }
        }
    }

    if (section)
        free(section);
    if (key)
        free(key);
    if (value)
        free(value);
}

int OverlayListGetEntriesFromBuffer(LinkedList *list, void *buffer, int size)
{
    if (!list)
        return -1;

    int res = 0;
    char *p = buffer;

    // Skip UTF-8 bom
    uint32_t bom = 0xBFBBEF;
    if (memcmp(p, &bom, 3) == 0)
    {
        p += 3;
        size -= 3;
    }

    OverlayEntryData *data = NULL;
    char *line = NULL;
    char *section = NULL;
    char *key = NULL;
    char *value = NULL;

    do
    {
        res = StringGetLine(p, size, &line);
        if (res > 0)
        {
            if (line)
            {
                // printf("GetLine: %s\n", line);
                if (StringParseLine(line, &section, &key, &value))
                {
                    // printf("ReadLine: section=%s, key=%s, value=%s\n", section ? section : "null", key ? key : "null", value ? value : "null");
                    getEntryData(list, &data, section, key, value);
                }
                free(line);
                line = NULL;
                section = NULL;
                key = NULL;
                value = NULL;
            }
            size -= res;
            p += res;
        }
    } while (res > 0);

    return 0;
}

int OverlayListGetEntries(LinkedList *list, const char *path)
{
    if (!list)
        return -1;

    void *buffer = NULL;
    size_t size = 0;
    if (AllocateReadFile(path, &buffer, &size) < 0)
        return -1;

    OverlayListGetEntriesFromBuffer(list, buffer, size);

    free(buffer);

    return 0;
}

LinkedList *NewOverlayList()
{
    LinkedList *list = NewLinkedList();
    if (!list)
        return NULL;

    LinkedListSetFreeEntryDataCallback(list, freeEntryData);
    return list;
}
